#ifndef M_FMT_H
#define M_FMT_H

#include"message.hpp"
#include<memory>
#include<vector>
#include<cctype>
#include<assert.h>

//1.行号 line  2.时间 ctime 3.线程id tid  4.日志器名称 name  5.文件名 file  6.日志消息 payload  7.日志等级 level
namespace bitlog{
    class FormatItem{
        public:
        using ptr=shared_ptr<FormatItem>;
        virtual void format(ostream& os,const LogMsg& msg)=0;
    };
    //1.行号
    class LineFormatItem:public FormatItem{
        public:
        LineFormatItem(const string& str=""){}
        void format(ostream& os,const LogMsg& msg) override
        {
            os<<msg._line;
        }
    };
    //2.时间
    class CtimeFormatItem:public FormatItem{
        private:
        string _str;
        public:
        CtimeFormatItem(const string& str="%H:%M:%S"):_str(str)
        {
            if(str.empty()) _str="%H:%M:%S";
        }
        void format(ostream& os,const LogMsg& msg) override
        {
            time_t time=msg._ctime;
            struct tm lt;
            localtime_r(&time,&lt);
            char tmp[128];
            strftime(tmp,127,_str.c_str(),&lt);
            os<<tmp;
        }
    };
    //3.线程id
    class TidFormatItem:public FormatItem{
        public:
        TidFormatItem(const string& str=""){}
        void format(ostream& os,const LogMsg& msg) override
        {
            os<<msg._tid;
        }
    };
    //4.日志器名称
    class NameFormatItem:public FormatItem{
        public:
        NameFormatItem(const string& str=""){}
        void format(ostream& os,const LogMsg& msg) override
        {
            os<<msg._name;
        }
    };
    //5.文件名
    class FileFormatItem:public FormatItem{
        public:
        FileFormatItem(const string& str=""){}
        void format(ostream& os,const LogMsg& msg) override
        {
            os<<msg._file;
        }
    };
    //6.消息主体
    class PayloadFormatItem:public FormatItem{
        public:
        PayloadFormatItem(const string& str=""){}
        void format(ostream& os,const LogMsg& msg) override
        {
            os<<msg._payload;
        }
    };
    //7.日志等级
    class LevelFormatItem:public FormatItem{
        public:
        LevelFormatItem(const string& str=""){}
        void format(ostream& os,const LogMsg& msg) override
        {
            os<<LogLevel::tostring(msg._level);
        }
    };
    //8."\n"
    class NlineFormatItem:public FormatItem{
        public:
        NlineFormatItem(const string& str=""){}
        void format(ostream& os,const LogMsg& msg) override{
            os<<"\n";
        }
    };
    //9."\t"
    class TabFormatItem:public FormatItem{
        public:
        TabFormatItem(const string& str=""){}
        void format(ostream& os,const LogMsg& msg) override
        {
            os<<"\t";
        }
    };
    //10.其他消息
    class OthersFormatItem:public FormatItem{
        private:
        string _str;
        public:
        OthersFormatItem(const string& str=""):_str(str){}
        void format(ostream& os,const LogMsg& msg) override
        {
            os<<_str;
        }
    };

    //1.行号 line  2.时间 ctime 3.线程id tid  4.日志器名称 name  5.文件名 file  6.日志消息 payload  7.日志等级 level
    // %d ⽇期
    // %T 缩进
    // %t 线程id
    // %p ⽇志级别
    // %c ⽇志器名称
    // %f ⽂件名
    // %l ⾏号
    // %m ⽇志消息
    // %n 换⾏
    class Formatter{
        private:
        string _pattern;
        vector<FormatItem::ptr> _items;
        public:
        using ptr=shared_ptr<Formatter>;
        Formatter(const string& pattern="[%d{%H:%M:%S}][%t][%p][%c][%f:%l] %m%n")
        {
            _pattern=pattern;
            assert(parsePattern());
        }
        string pattern(){return _pattern;}
        string format(const LogMsg& msg){
            stringstream ss;
            for(auto& e:_items)
            {
                e->format(ss,msg);
            }
            return ss.str();
        }
        ostream& format(ostream& os, LogMsg& msg){
            for(auto& e:_items)
            {
                e->format(os,msg);
            }
            return os;
        }
        FormatItem::ptr createItem(const string& fc,const string& subfmt)
        {
            if(fc=="d") return FormatItem::ptr(new CtimeFormatItem(subfmt));
            if(fc=="T") return FormatItem::ptr(new TabFormatItem(subfmt));
            if(fc=="l") return FormatItem::ptr(new LineFormatItem(subfmt));
            if(fc=="t") return FormatItem::ptr(new TidFormatItem(subfmt));
            if(fc=="p") return FormatItem::ptr(new LevelFormatItem(subfmt));
            if(fc=="c") return FormatItem::ptr(new NameFormatItem(subfmt));
            if(fc=="f") return FormatItem::ptr(new FileFormatItem(subfmt));
            if(fc=="m") return FormatItem::ptr(new PayloadFormatItem(subfmt));
            if(fc=="n") return FormatItem::ptr(new NlineFormatItem(subfmt));
            return FormatItem::ptr();
        }
        bool parsePattern()
        {
            // [%d{%H:%M:%S}][%t][%p][%c][%f:%l] %m%n
            vector<tuple<string,string,int>> arry;
            string format_key;
            string format_value;
            string string_row;
            bool sub_format_error=false;
            int pos=0;
            while(pos<_pattern.size())
            {
                if(_pattern[pos]!='%'){
                    string_row.append(1,_pattern[pos++]);
                    continue;
                }
                if(pos+1<_pattern.size()&&_pattern[pos+1]=='%'){
                    string_row.append(1,'%');
                    pos+=2;
                    continue;
                }
                if(string_row.empty()==false){
                    arry.push_back(make_tuple(string_row,"",0));
                    string_row.clear();
                }
                pos++;
                if(pos<_pattern.size()&&isalpha(_pattern[pos])){
                    format_key.append(1,_pattern[pos]);
                }else{
                    cout<<"%位置附近格式错误"<<endl;
                    return false;
                }
                pos+=1;
                if(pos<_pattern.size()&&_pattern[pos]=='{'){
                    sub_format_error=true;
                    pos++;
                    while(pos<_pattern.size()){
                        if(_pattern[pos]=='}'){
                            sub_format_error=false;
                            break;
                        }
                        format_value.append(1,_pattern[pos++]);
                    }
                }
                if(sub_format_error){
                    cout<<"{}格式错误"<<endl;
                    return false;
                }
                arry.push_back(make_tuple(format_key,format_value,1));
                format_key.clear();
                format_value.clear();
            }
            if(string_row.empty()==false) {arry.push_back(make_tuple(string_row,"",0));}
            if(format_key.empty()==false) {arry.push_back(make_tuple(format_key,format_value,1));}

            for(auto& it:arry){
                if(get<2>(it)==0){
                    FormatItem::ptr other(new OthersFormatItem(get<0>(it)));
                    _items.push_back(other);
                }else{
                    FormatItem::ptr fi=createItem(get<0>(it),get<1>(it));
                    if(fi.get()==nullptr){
                        cout<<"没有对应的格式化字符"<<endl;
                        return false;
                    }
                    _items.push_back(fi);
                }
            }
            return true;
        }
        
    };
}



#endif